﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Pahan.McuFusion.Common;

namespace Pahan.McuFusion.Files
{
    public static class FileFactory
    {
        static FileFactory()
        {
            RegisterReader("bin", "Flat Binary Files", typeof(BinaryFileReader));
            RegisterReader("hex", "Hex Files", typeof(IntelHexFileReader));
            RegisterReader("eep", "EEPROM Hex Files", typeof(IntelHexFileReader));

            RegisterWriter("bin", "Flat Binary File", typeof(BinaryFileWriter));
        }
        
        #region Public Members

        #region Readers

        public static void RegisterReader(String extension, String description, Type readerType)
        {
            RegisterReader(new FileTypeInfo(extension, description), readerType);
        }

        public static void RegisterReader(FileTypeInfo fileType, Type readerType)
        {
            Assert.NotNull(fileType, "fileType");
            Assert.NotNull(readerType, "readerType");
            if (!typeof(IFileReader).IsAssignableFrom(readerType))
            {
                throw new ArgumentException("The readerType does not implement IFileReader", "readerType");
            }
            if (readers.ContainsKey(fileType))
            {
                throw new InvalidOperationException("The reader for this extension is already registered.");
            }

            readers.Add(fileType, readerType);
        }
        
        public static IList<FileTypeInfo> GetReadableFileTypes()
        {
            return new List<FileTypeInfo>(readers.Keys);
        }

        public static IFileReader CreateReader(FileInfo file, byte defaultValue)
        {
            Assert.NotNull(file, "file");
            var fileType = new FileTypeInfo(file.Extension);
            if (!readers.ContainsKey(fileType))
            {
                throw new InvalidOperationException("Unknown file type.");
            }
            
            Stream fs = file.OpenRead();
            var reader = (IFileReader)Activator.CreateInstance(readers[fileType], fs);
            reader.DefaultValue = defaultValue;
            return reader;
        }

        #endregion

        #region Writers

        public static void RegisterWriter(String extension, String description, Type writerType)
        {
            RegisterWriter(new FileTypeInfo(extension, description), writerType);
        }

        public static void RegisterWriter(FileTypeInfo fileType, Type writerType)
        {
            Assert.NotNull(fileType, "fileType");
            Assert.NotNull(writerType, "writerType");
            if (!typeof(IFileWriter).IsAssignableFrom(writerType))
            {
                throw new ArgumentException("The writerType does not implement IFileWriter", "writerType");
            }
            if (writers.ContainsKey(fileType))
            {
                throw new InvalidOperationException("The writer for this extension is already registered.");
            }

            writers.Add(fileType, writerType);
        }

        public static IList<FileTypeInfo> GetWritableFileTypes()
        {
            return new List<FileTypeInfo>(writers.Keys);
        }

        public static IFileWriter CreateWriter(FileInfo file, byte defaultValue)
        {
            Assert.NotNull(file, "file");
            var fileType = new FileTypeInfo(file.Extension);
            if (!writers.ContainsKey(fileType))
            {
                throw new InvalidOperationException("Unknown file type.");
            }

            Stream fs = file.OpenWrite();
            var writer = (IFileWriter)Activator.CreateInstance(writers[fileType], fs);
            writer.DefaultValue = defaultValue;
            return writer;
        }

        #endregion

        #endregion

        #region Private Members

        private static readonly Dictionary<FileTypeInfo, Type> readers =
            new Dictionary<FileTypeInfo, Type>();

        private static readonly Dictionary<FileTypeInfo, Type> writers =
            new Dictionary<FileTypeInfo, Type>();

        #endregion
    }
}
